package cn.zhangfusheng.elasticsearch.constant.enumeration;

import cn.zhangfusheng.elasticsearch.exception.GlobalSystemException;
import cn.zhangfusheng.elasticsearch.model.es.EsRange;
import cn.zhangfusheng.elasticsearch.model.es.GeoDistance;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;

import java.util.Collection;

/**
 * 查询处理枚举
 * @author fusheng.zhang
 * @date 2022-04-25 11:00:36
 */
public enum SearchKeyword {
    MATCH_ALL("matchAll", (k, v) -> QueryBuilders.matchAllQuery()),
    MATCH("match", QueryBuilders::matchQuery),
    MULTI_MATCH("multiMatch", (k, v) -> QueryBuilders.multiMatchQuery(k, String.valueOf(v))),
    MATCH_PHRASE("matchPhrase", QueryBuilders::matchPhraseQuery),
    MATCH_PHRASE_PREFIX("matchPhrasePrefix", QueryBuilders::matchPhrasePrefixQuery),
    TERM("term", QueryBuilders::termQuery),
    FUZZY("fuzzy", QueryBuilders::fuzzyQuery),
    PREFIX("prefix", (k, v) -> QueryBuilders.prefixQuery(k, String.valueOf(v))),
    RANGE("range", (k, v) -> {
        if (v instanceof EsRange) {
            return ((EsRange) v).builder(QueryBuilders.rangeQuery(k));
        }
        throw new GlobalSystemException("range query params muster instanceof {}", EsRange.class.getName());
    }),
    WILDCARD("wildcard", (k, v) -> QueryBuilders.wildcardQuery(k, String.valueOf(v))),
    REGEXP("regexp", (k, v) -> QueryBuilders.regexpQuery(k, String.valueOf(v))),
    SPAN_TERM("spanTerm", (k, v) -> QueryBuilders.spanTermQuery(k, String.valueOf(v))),
    TERMS("terms", (k, v) -> {
        if (v instanceof Collection) {
            return QueryBuilders.termsQuery(k, (Collection<?>) v);
        }
        throw new GlobalSystemException("terms value master instanceof Collection");
    }),
    GEO_DISTANCE("geoDistance", (k, v) -> {
        if (v instanceof GeoDistance) {
            GeoDistance geoDistance = (GeoDistance) v;
            if (StringUtils.isBlank(geoDistance.getDistance())) return null;
            return QueryBuilders.geoDistanceQuery(k)
                    .point(geoDistance.getLat(), geoDistance.getLon())
                    .distance(geoDistance.getDistance(), geoDistance.getUnit())
                    .geoDistance(geoDistance.getGeoDistance());
        }
        throw new GlobalSystemException("geoDistanceQuery value master instanceof {}", GeoDistance.class.getName());
    }),
    GEO_BOUNDING_BOX("geoBoundingBox", (k, v) -> QueryBuilders.geoBoundingBoxQuery(k)),
    EXISTS("exists", (k, v) -> QueryBuilders.existsQuery(k)),
    ;


    private final String keyword;
    private final Builder builder;

    SearchKeyword(String keyword, Builder builder) {
        this.keyword = keyword;
        this.builder = builder;
    }

    public String getKeyword() {
        return keyword;
    }

    public QueryBuilder getBuilder(String key, Object value) {
        return builder.builder(key, value);
    }

    @FunctionalInterface
    interface Builder {
        QueryBuilder builder(String key, Object value);
    }
}
